﻿namespace Bridge.Base.Converter
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using Bridge.Base.Constructs;

    /// <summary>
    /// Base class for implementing a converter that outputs information in a file format. Should not be used to implement a character.
    /// </summary>
    public abstract class CharacterOutputConverter
    {
        /// <summary>
        /// Gets the <see cref="Type"/> of the real <see cref="Character"/>.
        /// </summary>
        /// <returns><see cref="Type"/> of <see cref="Character"/> this class implements.</returns>
        public abstract Type GetCharacterType();

        /// <summary>
        /// Gets the name of the converter.
        /// </summary>
        /// <returns><see cref="string"/> representing the name of the converter.</returns>
        public abstract string GetConverterName();

        /// <summary>
        /// Gets the description of the converter.
        /// </summary>
        /// <returns><see cref="string"/> representing the description of the converter.</returns>
        public abstract string GetConverterDescription();

        /// <summary>
        /// Gets the extensions filter that this output
        /// </summary>
        /// <returns><see cref="string"/> representing the extensions this converter can output as.</returns>
        /// <seealso cref="FileInfo"/>
        public abstract string GetOutputExtensions();

        /// <summary>
        /// Gets the default extension that this converter outputs as.
        /// </summary>
        /// <returns><see cref="string"/> representing the default extension any file output pointers should use.</returns>
        /// <seealso cref="FileInfo"/>
        public abstract string GetDefaultExtension();

        /// <summary>
        /// Outputs a character to the specified location.
        /// </summary>
        /// <param name="character"><see cref="Character"/> to output.</param>
        /// <param name="fileInfo"><see cref="FileInfo"/> to output to.</param>
        /// <param name="properties"><see cref="List{T}"/> properties to use for output.</param>
        /// <returns><b>True</b> if output succeeded; otherwise, false. Also false if the wrong <see cref="Character"/> type is put into the method.</returns>
        /// <remarks>This can also throw a number of exceptions to indicate full failure.</remarks>
        public abstract bool OutputCharacter(Character character, FileInfo fileInfo, List<ConverterProperty> properties);

        /// <summary>
        /// Gets the default <see cref="ConverterProperty"/> list.
        /// </summary>
        /// <returns>A <see cref="List<T>"/> of default converter properties.</returns>
        /// <remarks>When overriding this class, this method should be overridden as well.</remarks>
        public virtual List<ConverterProperty> GetConverterProperties()
        {
            return new List<ConverterProperty>();
        }

    }

    /// <summary>
    /// Base class for implementing a converter that outputs information in a file format.
    /// </summary>
    /// <typeparam name="T"><see cref="Character"/> type that implements this class.</typeparam>
    public abstract class CharacterOutputConverter<T> : CharacterOutputConverter where T : Character
    {
        /// <summary>
        /// Gets the <see cref="Type"/> of <see cref="Character"/> that this converter outputs.
        /// </summary>
        /// <returns><see cref="Type"/> of <see cref="Character"/> that this converter outputs.</returns>
        public override Type GetCharacterType()
        {
            return typeof(T);
        }

        /// <summary>
        /// Outputs a character to the specified location.
        /// </summary>
        /// <param name="character"><see cref="Character"/> to output.</param>
        /// <param name="fileInfo"><see cref="FileInfo"/> to output to.</param>
        /// <param name="properties"><see cref="List{T}"/> properties to use for output.</param>
        /// <returns><b>True</b> if output succeeded; otherwise, false. Also false if the wrong <see cref="Character"/> type is put into the method.</returns>
        /// <remarks>This can also throw a number of exceptions to indicate full failure.</remarks>
        public override bool OutputCharacter(Character character, FileInfo fileInfo, List<ConverterProperty> properties)
        {
            if (character is T)
            {
                return Output((T)character, fileInfo, properties);
            }
            return false;
        }

        /// <summary>
        /// Outputs a character to the specified location.
        /// </summary>
        /// <param name="character"><see cref="Character"/> to output.</param>
        /// <param name="fileInfo"><see cref="FileInfo"/> to output to.</param>
        /// <param name="properties"><see cref="List{T}"/> properties to use for output.</param>
        /// <returns><b>True</b> if output succeeded; otherwise, false. Also false if the wrong <see cref="Character"/> type is put into the method.</returns>
        /// <remarks>This can also throw a number of exceptions to indicate full failure.</remarks>
        public abstract bool Output(T character, FileInfo fileInfo, List<ConverterProperty> properties);
    }
}
